package controller

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"wms/define"
	"wms/logic"
	"wms/pkg/jwt"
)

// LoginHandler 用户登录接口
// @Summary 用户登录接口
// @Description 用户需要提交用户名和密码来登录账号
// @Tags 用户相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamUserLogin true "用户名和密码"
// @Success 200 {object} define.DocResponseData
// @Router /login [post]
func LoginHandler(c *gin.Context) {
	p := new(define.ParamUserLogin)
	if err := c.ShouldBindJSON(p); err != nil {
		zap.L().Error("Login with invalid param", zap.Error(err))
		errs, ok := err.(validator.ValidationErrors)
		if !ok {
			define.ResponseError(c, define.CodeInvalidParam)
			return
		}
		define.ResponseErrorWithMsg(c, define.CodeInvalidParam, define.RemoveTopStruct(errs.Translate(define.Trans)))
		return
	}
	//根据账号，密码查找用户
	ub, err := logic.GetUserBasic(p)
	if err != nil {
		zap.L().Error("logic.GetUserBasic failed", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}
	// 没找到匹配用户
	if ub.ID == 0 {
		zap.L().Error("logic.GetUserBasic failed", zap.String("error:", define.MysqlErrorPassword.Error()))
		define.ResponseError(c, define.CodeInvalidPassword)
		return
	}

	// 生成 Token
	aToken, rToken, _ := jwt.GenToken(ub.ID, ub.Identity, ub.Username, ub.RoleIdentity)

	define.ResponseSuccess(c, define.CodeSuccessLogin, gin.H{
		"access_token":  aToken,
		"refresh_token": rToken,
	})
}

// UpdateUserPasswordHandler 用户修改密码接口
// @Summary 用户修改密码接口
// @Description 认证后用户需要提交旧密码和新密码进行修改
// @Tags 用户相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamUserChangePassword true "旧密码和新密码"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/user/update/password [put]
func UpdateUserPasswordHandler(c *gin.Context) {
	p := new(define.ParamUserChangePassword)
	if err := c.ShouldBindJSON(p); err != nil {
		zap.L().Error("UserPasswordChange with invalid param", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}
	mc := c.MustGet("MyClaims").(*define.MyClaims)
	// 认证一下用户填写的原密码是否正确
	succ, err := logic.ConfirmOPassword(p, mc)
	if err != nil || !succ {
		zap.L().Error("UserPasswordChange with error opassword", zap.Error(err))
		if err != nil {
			define.ResponseError(c, define.CodeServerBusy)
			return
		}
		define.ResponseError(c, define.CodeOPasswordError)
		return
	}
	// 修改密码
	if err := logic.UserPasswordChange(p, mc); err != nil {
		zap.L().Error("UserPasswordChange failed", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessChangePwd, nil)
	return
}

// UpdateUserAvatarHandler 更新用户头像
// @Summary 用户更新头像接口
// @Description 认证后用户需要提供头像图片链接用以修改头像
// @Tags 用户相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamAvatar true "头像图片链接"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/user/update/avatar [put]
func UpdateUserAvatarHandler(c *gin.Context) {
	mc := c.MustGet("MyClaims").(*define.MyClaims)
	p := new(define.ParamAvatar)
	if err := c.ShouldBindJSON(p); err != nil {
		zap.L().Error("UpdateUserAvatarHandler bind json failed", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	if err := logic.UpdateUserAvatar(mc.Identity, p); err != nil {
		zap.L().Error("logic.UpdateUserAvatar failed", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessUpdateAvatar, nil)
}

// GetUserListHandler 获取用户列表
// @Summary 获取用户列表接口
// @Description 鉴权后用户需要提交分页信息获取对应用户列表
// @Tags 用户相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamUserListPage true "分页信息"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/user/get/list [get]
func GetUserListHandler(c *gin.Context) {
	p := new(define.ParamUserListPage)
	if err := c.ShouldBindQuery(p); err != nil {
		zap.L().Error("SetUserList bind query param failed", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	userListCnt, userLists, err := logic.GetUserList(p)
	if err != nil {
		zap.L().Error("logic.GetUserList failed", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessGetUserList, gin.H{
		"userList":    userLists,
		"userListCnt": userListCnt,
	})
}

// GetUserDetailHandler 获取用户详情
// @Summary 获取用户详情信息接口
// @Description 鉴权后用户需要提交用户唯一标识获取对应用户详情个人信息，如果没有提供则查询自己个人详情
// @Tags 用户相关接口
// @Accept application/json
// @Produce application/json
// @Param Identity query string false "用户标识"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/user/get/detail [get]
func GetUserDetailHandler(c *gin.Context) {
	mc := c.MustGet("MyClaims").(*define.MyClaims)
	identity := c.Query("identity")
	if identity == "" {
		// 如果未提交指定用户的ID，那么获取自己的信息
		identity = mc.Identity
	}
	p := new(define.UserDetailReply)
	if err := logic.GetUserDetail(identity, p); err != nil {
		zap.L().Error("logic.GetUserDetail failed", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}
	define.ResponseSuccess(c, define.CodeSuccessGetUserDetail, p)
}

// CreateUserHandler 创建用户
// @Summary 创建用户接口
// @Description 鉴权后用户需要提交用户基本信息创建用户
// @Tags 用户相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamUserAdd true "用户基本信息"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/user/create [post]
func CreateUserHandler(c *gin.Context) {
	p := new(define.ParamUserAdd)
	if err := c.ShouldBindJSON(p); err != nil {
		zap.L().Error("CreateUser bind param failed", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	if p.Password == "" {
		// 密码不能为空，更新用户的时候可以密码是空
		zap.L().Error("CreateUser param password is null")
		define.ResponseError(c, define.CodePasswordIsNull)
		return
	}

	if err := logic.CreateUser(p); err != nil {
		zap.L().Error("logic.CreateUser failed", zap.Error(err))
		if errors.Is(err, define.MysqlErrorUsernameExist) {
			// 用户名已存在
			define.ResponseError(c, define.CodeUsernameExist)
			return
		}
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessCreateUser, nil)
}

// UpdateUserHandler 更新用户
// @Summary 更新用户接口
// @Description 鉴权后用户需要提交用户信息更新用户
// @Tags 用户相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamUser true "用户信息"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/user/update [put]
func UpdateUserHandler(c *gin.Context) {
	p := new(define.ParamUser)
	if err := c.ShouldBindJSON(p); err != nil {
		zap.L().Error("UpdateUser bind param failed", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	if err := logic.UpdateUser(p); err != nil {
		zap.L().Error("logic.UpdateUser failed", zap.Error(err))
		if errors.Is(err, define.MysqlErrorUsernameExist) {
			define.ResponseError(c, define.CodeUsernameExist)
			return
		}
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessUpdateUser, nil)
}

// DeleteUserHandler 删除用户
// @Summary 删除用户接口
// @Description 鉴权后用户需要提交用户唯一标识删除用户
// @Tags 用户相关接口
// @Accept application/json
// @Produce application/json
// @Param Identity query string true "用户标识"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/user/delete [delete]
func DeleteUserHandler(c *gin.Context) {
	identity := c.Query("identity")
	if identity == "" {
		zap.L().Error("DeleteUser bind query param failed")
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	if err := logic.DeleteUser(identity); err != nil {
		zap.L().Error("logic.DeleteUserByIdentity failed", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessDelUser, nil)
}
